﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Packaging;
using System.Collections.Concurrent;

namespace Uzi.Packaging
{
    public static class BasePartHelper
    {
        private static ConcurrentDictionary<string, IBasePartFactory> _Factories = new ConcurrentDictionary<string, IBasePartFactory>();

        public static void RegisterFactory(IBasePartFactory factory)
        {
            foreach (var _rType in factory.Relationships)
                _Factories.AddOrUpdate(_rType, factory, (name, f) =>
                {
                    return f;
                });
        }

        #region public static IEnumerable<IBasePart> Relationships(this PackageRelationshipCollection relations, ICorePartNameManager manager)
        /// <summary>Provides IBaseParts implied by this relationship collection</summary>
        public static IEnumerable<IBasePart> Relationships(this PackageRelationshipCollection relations, ICorePartNameManager manager)
        {
            foreach (var _relation in relations)
            {
                PackagePart _part = _relation.Package.GetPart(_relation.TargetUri);
                var _factory = _Factories[_relation.RelationshipType];
                if (_factory != null)
                    yield return _factory.GetPart(_relation.RelationshipType, manager, _part, _relation.Id);
                else
                    yield return new UnknownPart(manager, _part, _relation.Id, _relation.RelationshipType);
            }
            yield break;
        }
        #endregion

        #region public static IBasePart FindPart(this ICorePart source, string internalPath)
        /// <summary>Finds a part given its internal path</summary>
        public static IBasePart FindPart(this ICorePart source, string internalPath)
        {
            var _current = source;
            var _pathParts = internalPath.Split('/');
            foreach (var _part in _pathParts)
            {
                _current = _current.Relationships.FirstOrDefault(_p => _p.Name.Equals(_part, StringComparison.InvariantCultureIgnoreCase));
                if (_current == null)
                    break;
            }
            return _current as IBasePart;
        }
        #endregion

        #region public static string GetInternalPath(this IBasePart part)
        /// <summary>Climbs name manager tree to build an internal path for this part</summary>
        public static string GetInternalPath(this IBasePart part)
        {
            var _builder = new StringBuilder(string.Format(@"/{0}", part.Name));
            var _mgr = part.NameManager;
            while (_mgr != null)
            {
                var _part = _mgr as IBasePart;
                if (_part != null)
                {
                    _builder.Insert(0, string.Format(@"/{0}", _part.Name));
                    _mgr = _part.NameManager;
                }
                else
                    _mgr = null;
            }
            return _builder.ToString();
        }
        #endregion
    }
}
